#!/bin/bash

# MySQL新增从库脚本
# 作者: MySQL Demo
# 版本: 1.5
# 
# 解决方案说明：
# 1. 避免导入系统表：只dump应用数据库(testdb)，不导入mysql系统表，避免权限冲突
# 2. 正确的网络配置：使用mysql-ha_mysql-cluster网络
# 3. 认证插件配置：使用mysql_native_password认证
# 4. 权限重新设置：在关键步骤后重新设置root用户权限
# 5. 解决ERROR 1130权限问题：通过上述配置确保连接正常
# 6. 移除不必要的host和port参数：在Docker容器内部直接连接，避免连接问题
# 7. 改进等待逻辑：确保MySQL完全初始化后再继续操作

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 显示帮助信息
show_help() {
    echo "MySQL新增从库脚本"
    echo
    echo "用法: $0 [选项] <从库名称>"
    echo
    echo "选项:"
    echo "  -p, --port <端口>      指定从库端口 (默认: 3310)"
    echo "  -s, --server-id <ID>   指定server-id (默认: 5)"
    echo "  -h, --help             显示此帮助信息"
    echo
    echo "示例:"
    echo "  $0 slave3              # 创建从库slave3"
    echo "  $0 -p 3311 slave4      # 创建从库slave4，端口3311"
}

# 检查参数
check_arguments() {
    if [ $# -eq 0 ]; then
        log_error "缺少从库名称参数"
        show_help
        exit 1
    fi
    
    # 解析参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            -p|--port)
                SLAVE_PORT="$2"
                shift 2
                ;;
            -s|--server-id)
                SERVER_ID="$2"
                shift 2
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            -*)
                log_error "未知选项: $1"
                show_help
                exit 1
                ;;
            *)
                SLAVE_NAME="$1"
                shift
                ;;
        esac
    done
    
    # 设置默认值
    SLAVE_PORT=${SLAVE_PORT:-3310}
    SERVER_ID=${SERVER_ID:-5}
    
    # 验证参数
    if [ -z "$SLAVE_NAME" ]; then
        log_error "缺少从库名称参数"
        show_help
        exit 1
    fi
    
    log_success "参数验证通过"
    log_info "从库名称: $SLAVE_NAME"
    log_info "端口: $SLAVE_PORT"
    log_info "Server ID: $SERVER_ID"
}

# 检查Docker环境
check_docker() {
    if ! command -v docker &> /dev/null; then
        log_error "Docker未安装"
        exit 1
    fi
    
    log_success "Docker环境检查通过"
}

# 检查集群状态
check_cluster_status() {
    log_info "检查集群状态..."
    
    if ! docker exec mysql-master mysqladmin ping -u root -proot123 --silent; then
        log_error "主库服务异常"
        exit 1
    fi
    
    if ! docker exec mysql-backup mysqladmin ping -u root -proot123 --silent; then
        log_error "备库服务异常"
        exit 1
    fi
    
    log_success "集群状态检查通过"
}

# 创建从库目录
create_slave_directories() {
    log_info "创建从库目录..."
    
    mkdir -p mysql-data/$SLAVE_NAME
    mkdir -p mysql-config/$SLAVE_NAME
    mkdir -p mysql-logs/$SLAVE_NAME
    
    log_success "从库目录创建完成"
}

# 创建从库配置文件
create_slave_config() {
    log_info "创建从库配置文件..."
    
    cat > mysql-config/$SLAVE_NAME/my.cnf << EOF
[mysqld]
server-id = $SERVER_ID
port = 3306
bind-address = 0.0.0.0

default_authentication_plugin = mysql_native_password

log-bin = mysql-bin
binlog_format = ROW

relay-log = mysql-relay-bin
relay-log-index = mysql-relay-bin.index
relay-log-info-file = mysql-relay-bin.info

character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_log_buffer_size = 16M

gtid_mode = ON
enforce_gtid_consistency = ON

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

log-error = /var/log/mysql/error.log
log-error-verbosity = 3
EOF

    log_success "从库配置文件创建完成"
}

# 从备库dump数据
dump_data_from_backup() {
    log_info "从备库dump数据..."
    
    local dump_file="backup/slave_dump_${SLAVE_NAME}_$(date +%Y%m%d_%H%M%S).sql"
    
    mkdir -p backup
    
    # 解决方案：只dump应用数据库的表结构，不dump系统数据库，避免权限冲突
    # 避免ERROR 1130: Host '127.0.0.1' is not allowed to connect to this MySQL server
    docker exec mysql-backup mysqldump -u root -proot123 \
        --no-data \
        --routines \
        --triggers \
        --events \
        --set-gtid-purged=OFF \
        testdb \
        > "$dump_file"
    
    if [ $? -eq 0 ]; then
        log_success "表结构dump完成: $dump_file"
        echo "$dump_file" > /tmp/last_dump_file.txt
    else
        log_error "表结构dump失败"
        exit 1
    fi
}

# 创建新从库容器
create_new_slave_container() {
    log_info "创建新从库容器..."
    
    # 检查网络是否存在
    if ! docker network ls | grep -q "mysql-ha_mysql-cluster"; then
        log_error "mysql-ha_mysql-cluster 网络不存在，请先启动集群"
        exit 1
    fi
    
    # 解决方案：使用正确的网络和认证插件配置，避免权限问题
    docker run -d \
        --name mysql-$SLAVE_NAME \
        --hostname mysql-$SLAVE_NAME \
        --network mysql-ha_mysql-cluster \
        -p $SLAVE_PORT:3306 \
        -e MYSQL_ROOT_PASSWORD=root123 \
        -e MYSQL_DATABASE=testdb \
        -e MYSQL_USER=appuser \
        -e MYSQL_PASSWORD=app123 \
        -v $(pwd)/mysql-data/$SLAVE_NAME:/var/lib/mysql \
        -v $(pwd)/mysql-config/$SLAVE_NAME:/etc/mysql/conf.d \
        -v $(pwd)/mysql-logs/$SLAVE_NAME:/var/log/mysql \
        mysql:8.0 \
        --default-authentication-plugin=mysql_native_password \
        --authentication-policy=mysql_native_password
    
    if [ $? -eq 0 ]; then
        log_success "新从库容器创建成功"
        
        # 验证容器是否在正确的网络中
        local network_check=$(docker inspect mysql-$SLAVE_NAME --format='{{range $net, $config := .NetworkSettings.Networks}}{{$net}} {{end}}')
        if echo "$network_check" | grep -q "mysql-ha_mysql-cluster"; then
            log_success "新从库已正确加入 mysql-ha_mysql-cluster 网络"
        else
            log_error "新从库未正确加入 mysql-ha_mysql-cluster 网络"
            exit 1
        fi
    else
        log_error "新从库容器创建失败"
        exit 1
    fi
}

# 等待新从库就绪
wait_for_new_slave() {
    log_info "等待新从库服务就绪..."
    
    local max_attempts=30
    local attempt=1
    
    while [ $attempt -le $max_attempts ]; do
        if docker exec mysql-$SLAVE_NAME mysqladmin ping -u root -proot123 --silent; then
            log_success "新从库服务就绪"
            break
        fi
        
        log_info "等待新从库服务就绪... (尝试 $attempt/$max_attempts)"
        sleep 10
        attempt=$((attempt + 1))
    done
    
    if [ $attempt -gt $max_attempts ]; then
        log_error "新从库服务启动超时"
        exit 1
    fi
    
    # 额外等待，确保MySQL完全初始化
    log_info "等待MySQL完全初始化..."
    sleep 20
    
    # 再次验证MySQL服务是否真正可用
    local retry_count=0
    while [ $retry_count -lt 5 ]; do
        if docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "SELECT 1;" > /dev/null 2>&1; then
            log_success "MySQL服务完全就绪"
            break
        fi
        log_info "等待MySQL服务完全就绪... (重试 $((retry_count + 1))/5)"
        sleep 5
        retry_count=$((retry_count + 1))
    done
    
    if [ $retry_count -eq 5 ]; then
        log_error "MySQL服务初始化失败"
        exit 1
    fi
}

# 测试网络连接
test_network_connectivity() {
    log_info "测试网络连接..."
    
    # 测试从新从库到主库的MySQL连接（跳过ping测试，因为MySQL容器没有ping命令）
    if docker exec mysql-$SLAVE_NAME mysql -h mysql-master -P 3306 -u repl -prepl123 -e "SELECT 1;" > /dev/null 2>&1; then
        log_success "新从库可以连接到主库MySQL"
    else
        log_error "新从库无法连接到主库MySQL"
        return 1
    fi
    
    # 测试从新从库到主库的root用户连接
    if docker exec mysql-$SLAVE_NAME mysql -h mysql-master -P 3306 -u root -proot123 -e "SELECT 1;" > /dev/null 2>&1; then
        log_success "新从库可以使用root用户连接到主库MySQL"
    else
        log_error "新从库无法使用root用户连接到主库MySQL"
        return 1
    fi
}

# 导入数据到新从库
import_data_to_slave() {
    log_info "导入表结构到新从库..."
    
    local dump_file=$(cat /tmp/last_dump_file.txt)
    
    if [ ! -f "$dump_file" ]; then
        log_error "找不到dump文件"
        exit 1
    fi
    
    # 解决方案：指定数据库名称，避免"No database selected"错误
    docker exec -i mysql-$SLAVE_NAME mysql -u root -proot123 testdb < "$dump_file"
    
    if [ $? -eq 0 ]; then
        log_success "表结构导入完成"
        
        # 清理GTID状态，避免与主库冲突
        log_info "清理GTID状态..."
        docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "
            RESET MASTER;
            SET @@GLOBAL.GTID_PURGED='';
        "
        log_success "GTID状态清理完成"
        
        # 解决方案：重新设置root用户权限，确保连接正常
        log_info "重新设置root用户权限..."
        docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "
            CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY 'root123';
            GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
            FLUSH PRIVILEGES;
        " 2>/dev/null || log_warning "无法重新设置root权限，可能权限已正确"
    else
        log_error "表结构导入失败"
        exit 1
    fi
}

# 配置新从库复制
setup_slave_replication() {
    log_info "配置新从库复制..."
    
    # 解决方案：先确保root用户权限正确，避免ERROR 1130权限问题
    log_info "确保root用户权限..."
    docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "
        CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY 'root123';
        GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
        FLUSH PRIVILEGES;
    " 2>/dev/null || log_warning "无法设置root权限，可能权限已正确"
    
    docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "
        STOP REPLICA;
        RESET REPLICA ALL;
        CHANGE REPLICATION SOURCE TO
            SOURCE_HOST = 'mysql-master',
            SOURCE_PORT = 3306,
            SOURCE_USER = 'repl',
            SOURCE_PASSWORD = 'repl123',
            SOURCE_AUTO_POSITION = 1;
        START REPLICA;
    "
    
    if [ $? -eq 0 ]; then
        log_success "复制配置完成"
    else
        log_error "复制配置失败"
        exit 1
    fi
    
    # 启用只读模式
    docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "
        SET GLOBAL read_only = 1;
        SET GLOBAL super_read_only = 1;
    "
    
    log_success "新从库只读模式已启用"
}

# 验证新从库状态
verify_slave_status() {
    log_info "验证新从库状态..."
    
    if docker exec mysql-$SLAVE_NAME mysqladmin ping -u root -proot123 --silent; then
        log_success "新从库服务状态正常"
    else
        log_error "新从库服务状态异常"
        return 1
    fi
    
    local replica_status=$(docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e "SHOW REPLICA STATUS\G" | grep -E "(Replica_IO_Running|Replica_SQL_Running|Seconds_Behind_Master)" | head -3)
    log_info "新从库复制状态: $replica_status"
    
    log_success "新从库状态验证完成"
}

# 更新HAProxy配置
update_haproxy_config() {
    log_info "更新HAProxy配置..."
    
    # 检查HAProxy配置文件是否存在
    if [ ! -f "haproxy.cfg" ]; then
        log_warning "HAProxy配置文件不存在，跳过配置更新"
        return 0
    fi
    
    # 备份原配置文件
    cp haproxy.cfg haproxy.cfg.backup.$(date +%Y%m%d_%H%M%S)
    
    # 在从库服务器组中添加新从库
    # 使用临时文件来处理sed命令
    cp haproxy.cfg haproxy.cfg.tmp
    awk -v slave_name="$SLAVE_NAME" '
    /server mysql-slave2/ {
        print $0
        print "    server mysql-" slave_name " mysql-" slave_name ":3306 check"
        next
    }
    { print $0 }
    ' haproxy.cfg.tmp > haproxy.cfg
    rm haproxy.cfg.tmp
    
    # 重启HAProxy容器
    if docker ps --format "{{.Names}}" | grep -q "mysql-haproxy"; then
        docker restart mysql-haproxy
        if [ $? -eq 0 ]; then
            log_success "HAProxy配置更新完成"
        else
            log_error "HAProxy重启失败"
            return 1
        fi
    else
        log_warning "HAProxy容器不存在，跳过重启"
    fi
}

# 清理临时文件
cleanup_temp_files() {
    log_info "清理临时文件..."
    rm -f /tmp/last_dump_file.txt
    log_success "临时文件清理完成"
}

# 显示完成信息
show_completion_info() {
    log_success "新从库添加完成！"
    echo
    echo "=== 新从库信息 ==="
    echo "从库名称: mysql-$SLAVE_NAME"
    echo "端口: $SLAVE_PORT"
    echo "Server ID: $SERVER_ID"
    echo "连接信息: localhost:$SLAVE_PORT (root/root123)"
    echo
    echo "=== 测试连接 ==="
    echo "mysql -h localhost -P $SLAVE_PORT -u root -p"
    echo
    echo "=== 检查复制状态 ==="
    echo "docker exec mysql-$SLAVE_NAME mysql -u root -proot123 -e \"SHOW REPLICA STATUS\\G\""
    echo
    echo "=== 解决方案说明 ==="
    echo "已解决ERROR 1130权限问题："
    echo "- 避免导入系统表，只导入应用数据库"
    echo "- 使用正确的网络配置"
    echo "- 配置认证插件"
    echo "- 重新设置用户权限"
}

# 主函数
main() {
    echo "=========================================="
    echo "    MySQL新增从库脚本"
    echo "=========================================="
    echo
    
    check_arguments "$@"
    check_docker
    check_cluster_status
    create_slave_directories
    create_slave_config
    dump_data_from_backup
    create_new_slave_container
    wait_for_new_slave
    test_network_connectivity
    import_data_to_slave
    setup_slave_replication
    verify_slave_status
    update_haproxy_config
    cleanup_temp_files
    show_completion_info
    
    echo
    log_success "新从库添加流程完成！"
}

# 执行主函数
main "$@"
